package com.mioto.ld.communication.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author mioto-qinxj
 * @date 2024/5/16
 * @desc
 */
@Slf4j
@Component
public class WebsocketServer implements ApplicationRunner {
    /**
     * 处理Accept连接事件的线程，这里线程数设置为1即可，netty处理链接事件默认为单线程，过度设置反而浪费cpu资源
     */
    protected EventLoopGroup bossGroup;
    /**
     * 处理handler的工作线程，其实也就是处理IO读写 。线程数据默认为 CPU 核心数乘以2
     */
    protected EventLoopGroup workGroup;
    protected ChannelFuture channelFuture;
    /**
     * 自定义服务器通道初始化器
     */
    @Resource
    private WebsocketServerChannelInitializer websocketServerChannelInitializer;

    protected int port;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        start();
    }

    /**
     * 服务启动
     */
    public void start(){
        bossGroup = new NioEventLoopGroup(1);
        workGroup = new NioEventLoopGroup();
        //创建主线程一个主线程
        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(bossGroup, workGroup)
                //指定通道类型
                .channel(NioServerSocketChannel.class)
                //在ServerChannelInitializer中初始化ChannelPipeline责任链，并添加到serverBootstrap中
                .childHandler(websocketServerChannelInitializer)
                //标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
                .option(ChannelOption.SO_BACKLOG, 1024)
                // 是否启用心跳保活机机制
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        try {
            //绑定端口,开始接收进来的连接
            channelFuture = bootstrap.bind(port).sync();
            if (channelFuture.isSuccess()) {
                log.info("websocket server started! server port is: {}", port);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdown()));
        }
    }

    /**
     * 销毁服务
     */
    protected void shutdown() {
        if (channelFuture != null) {
            channelFuture.channel().close().syncUninterruptibly();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workGroup != null) {
            workGroup.shutdownGracefully();
        }
        log.info("websocket server destroy");
    }

    /**
     * 重启服务
     */
    protected void restart() {
        shutdown();
        start();
    }

    @Value("${websocket.port:8991}")
    protected void setPort(int port){
        this.port = port;
    }


}
